﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DoNet.Common.Utilities
{
    /// <summary>
    /// 表单与实体之间自动赋值类
    /// 表单=>实体
    /// 实体=>表单
    /// </summary>
    /// <typeparam name="T">实体类</typeparam>
    public partial class FormHelper<T>
    {
        #region 单实例 FormHelper<T>.Instance

        private static FormHelper<T> _instance = new FormHelper<T>();  
      
        /// <summary>
        /// 单实例
        /// </summary>
        public static FormHelper<T> Instance
        {
            get
            {
                if (_instance != null)
                {
                    lock (typeof(FormHelper<T>))
                    {
                        return new FormHelper<T>();
                    }
                }
                return _instance;
            }
        }

        protected FormHelper()
        {

        }

        #endregion 

        #region 公共方法 
        /// <summary>
        /// 表单自动更新实体
        /// </summary>
        /// <param name="myFrom">控件ID</param>
        /// <param name="t">实体类</param>
        public void UpdateModel(Control myFrom, T t)
        {
            PropertyInfo[] pi = GetPropertiesEx(t);

            foreach (PropertyInfo p in pi)
            {
                if (p != null && p.CanWrite)
                {
                    SetValueEx(p, GetControlValue(myFrom, p.Name), t);
                }

            }
        }

        /// <summary>
        /// 实体自动填充表单
        /// </summary>
        /// <param name="myFrom">控件容器</param>
        /// <param name="t">实体类</param>
        public void FillForm(Control myFrom, T t)
        {

            PropertyInfo[] pi = GetPropertiesEx(t);

            foreach (PropertyInfo p in pi)
            {
                if (p != null && p.CanRead)
                {
                    //获得实体值
                    object obj = p.GetValue(t, null);

                    Control control = FindControlEx(myFrom, p.Name);
                    if (control != null)
                    {
                        SetFormValue(control, obj);
                    }
                }

               
            }
        }

        //// <summary>
        /// 递归查找找指定ID的控件
        /// </summary>
        /// <param name="Parent">父控件(控件容器)</param>
        /// <param name="id">要查找的控件ID</param>
        /// <returns>回传符合ID的控件，若未找到则返回Null</returns>
        public System.Web.UI.Control FindControlEx(System.Web.UI.Control Parent, string id)
        {
            
            System.Web.UI.Control oCtrl = null;

            //先使用 FindControl 去查找指定的子控件
            oCtrl = Parent.FindControl(id);

            //如果未找到则往下层递归方式去查找
            if (oCtrl == null)
            {
                foreach (System.Web.UI.Control oChildCtrl in Parent.Controls)
                {
                    //以递归方式回调原函数
                    oCtrl = FindControlEx(oChildCtrl, id);

                    //如果找到指定控件则退出循环
                    if (oCtrl != null && oCtrl.ID == id)
                    {
                        break;
                    }
                }
            }
            return oCtrl;
        }
        #endregion

        #region 私有方法
        /// <summary>
        /// 获取实体类属性集合
        /// </summary>
        /// <param name="t">实体类</param>
        /// <returns>实体类属性集合</returns>
        private PropertyInfo[] GetPropertiesEx(T t)
        {
            return t.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
        }

        /// <summary>
        /// 动态给控件赋值
        /// </summary>
        /// <param name="control">控件ID</param>
        /// <param name="obj">值</param>
        private void SetFormValue(Control control, object obj)
        {

            switch (control.GetType().Name)
            {
                case "TextBox":
                    TextBox txt = control as TextBox;
                    txt.Text = obj.ToString();
                    break;

                case "Label":
                    Label lbl = control as Label;
                    lbl.Text = obj.ToString();
                    break;
                case "DropDownList":
                    DropDownList ddl = control as DropDownList;
                    ddl.SelectedValue = obj.ToString();
                    break;

                case "RadioButtonList":
                    RadioButtonList rbl = control as RadioButtonList;
                    if (obj.ToString().ToLower() == "true")
                    {
                        obj = "1";
                    }
                    else
                    {
                        obj = "0";
                    }
                    rbl.SelectedValue = obj.ToString();
                    break;
                case "CheckBoxList":
                    CheckBoxList chk = control as CheckBoxList;

                    string[] temp = obj.ToString().Split(',');

                    foreach (string s in temp)
                    {
                        foreach (ListItem ls in chk.Items)
                        {
                            if (ls.Value.Equals(s))
                            {
                                ls.Selected = true;
                            }
                        }
                    }
                    break;
                default:
                    //tempVlue = System.Web.HttpContext.Current.Request[control.GetType().Name];
                    break;
            }
        }

        /// <summary>
        /// 动态为实体属性赋值
        /// </summary>
        /// <param name="pi">属性信息类型</param>
        /// <param name="obj">值</param>
        /// <param name="t">实体类</param>
        private void SetValueEx(PropertyInfo pi, object obj, T t)
        {
            Type typeName = pi.PropertyType;

            if (typeName == typeof(string))
            {
                pi.SetValue(t, obj, null);
                return;
            }


            if (typeName == typeof(int) ||typeName==typeof(int?)|| typeName == typeof(float) || typeName == typeof(double) || typeName == typeof(decimal))
            {
                if (string.IsNullOrEmpty(obj.ToString().Trim()))
                {
                    obj = -1;
                    pi.SetValue(t, obj, null);
                    return;
                }
                else
                {
                    if (typeName == typeof(int)||typeName==typeof(int?))
                    {
                        int result;

                        if (int.TryParse(obj.ToString(), out result))
                        {
                            obj = result;
                        }
                        else
                        {
                            obj = -1;
                        }
                        pi.SetValue(t, obj, null);
                        return;
                    }

                    if (typeName == typeof(float))
                    {
                        float result;

                        if (float.TryParse(obj.ToString(), out result))
                        {
                            obj = result;
                        }
                        else
                        {
                            obj = -1;
                        }
                        pi.SetValue(t, obj, null);
                        return;
                    }

                    if (typeName == typeof(double))
                    {
                        double result;

                        if (double.TryParse(obj.ToString(), out result))
                        {
                            obj = result;
                        }
                        else
                        {
                            obj = -1;
                        }
                        pi.SetValue(t, obj, null);
                        return;
                    }

                    if (typeName == typeof(decimal))
                    {
                        decimal result;

                        if (decimal.TryParse(obj.ToString(), out result))
                        {
                            obj = result;
                        }
                        else
                        {
                            obj = -1;
                        }
                        pi.SetValue(t, obj, null);
                        return;
                    }
                }

            }

            if (typeName == typeof(DateTime))
            {
                if (string.IsNullOrEmpty(obj.ToString().Trim()))
                {
                    obj = DateTime.Parse("1900-01-01 00:00:00");
                }
                else
                {
                    DateTime result;
                    if (DateTime.TryParse(obj.ToString(), out result))
                    {
                        obj = result;
                    }
                    else
                    {
                        obj = DateTime.Parse("1900-01-01 00:00:00");
                    }
                }
                pi.SetValue(t, obj, null);
            }

            if (typeName == typeof(bool)||typeName==typeof(bool?))
            {
                if (string.IsNullOrEmpty(obj.ToString().Trim()))
                {
                    obj = false;
                }
                else
                {
                    if (obj.ToString() == "1" || obj.ToString().ToLower() == "true")
                    {
                        obj = true;
                    }
                    else
                    {
                        obj = false;
                    }
                }
                pi.SetValue(t, obj, null);
            }
        }

        /// <summary>
        /// 动态获取控件值
        /// </summary>
        /// <param name="myFrom">控件容器</param>
        /// <param name="controlName">控件ID</param>
        /// <returns></returns>
        private object GetControlValue(Control myFrom, string controlName)
        {
            Control control = FindControlEx(myFrom, controlName);
            string tempVlue = string.Empty;

            if (control != null)
            {
                string controlType = control.GetType().Name;
                if (controlType.Substring(0, 3).Equals("Web"))
                {
                    controlType = controlType.Replace("Web", "");
                }
                switch (controlType)
                {
                    case "TextBox":
                        TextBox txt = control as TextBox;
                        tempVlue = txt.Text.Trim();
                        break;
                    case "Label":
                        Label lbl = control as Label;
                        tempVlue = lbl.Text.Trim();
                        break;
                    case "HiddenField":
                        HiddenField hdf = control as HiddenField;
                        tempVlue = hdf.Value.Trim();
                        break;
                    case "DropDownList":
                        DropDownList ddl = control as DropDownList;
                        tempVlue = ddl.SelectedValue.Trim();
                        break;
                    case "RadioButtonList":
                        RadioButtonList rbl = control as RadioButtonList;
                        tempVlue = rbl.SelectedValue.Trim();
                        break;
                    case "CheckBoxList":
                        CheckBoxList chk = control as CheckBoxList;
                        foreach (ListItem lit in chk.Items)
                        {
                            if (lit.Selected)
                            {
                                tempVlue = tempVlue + "," + lit.Value.Trim();
                            }
                        }
                        if (tempVlue.Length > 0)
                        {
                            tempVlue = tempVlue.Remove(0, 1);
                        }
                        break;
                    default:
                        tempVlue = System.Web.HttpContext.Current.Request[control.GetType().Name];
                        break;
                }
            }

            return tempVlue;
        }

        #endregion
    }
}
